/*	talmud - The TALMUD roguelike
 * Copyright (C) 2012, talmud contributors
 *
 *  This program is free software; you can redistribute it and/or modify it
 *  under the terms of Version 2 of the GNU General Public License as published
 *  by the Free Software Foundation.
 *
 *  This program is distributed in the hope that it will be useful, but WITHOUT
 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 *  FITNESS FOR A PARTICULAR PURPOSE. See Version 2 of the GNU General Public
 *  License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "itemmanage.h"
#include "talmud.h"
#include "item.h"
#include "rand.h"
#include "draw.h"

static const char ITEMREPS[I_CATCOUNT] = {
	')',
	'[',
	'/',
	'!',
	'?',
	'+',
	'(',
	'*',
};

static const uint8_t ITEMGENSLOTS[I_CATCOUNT] = {
	5,	// weapon
	5,	// armor
	7,	// wand
	8,	// potion
	7,	// scroll
	4,	// book
	4,	// tool
	10,	// misc
};

static const uint8_t ITEMGENSLOTBASE[I_CATCOUNT] = {
	ID_WEAPON_BASE,
	ID_ARMOR_BASE,
	ID_WAND_BASE,
	ID_POTION_BASE,
	ID_SCROLL_BASE,
	ID_BOOK_BASE,
	ID_TOOL_BASE,
	ID_MISC_BASE,
};

static const uint8_t ITEMGENSLOTCOUNT[I_CATCOUNT] = {
	ID_WEAPON_COUNT,
	ID_ARMOR_COUNT,
	ID_WAND_COUNT,
	ID_POTION_COUNT,
	ID_SCROLL_COUNT,
	ID_BOOK_COUNT,
	ID_TOOL_COUNT,
	ID_MISC_COUNT,
};

static const char * const UNIDED_WAND_SRCS[W_COUNT] = {
	"unadorned wand",	// 1
	"long wand",		// 2
	"short wand",		// 3
	"crystal wand",		// 4
	"wooden wand",		// 5
	"brass wand",		// 6
	"bronze wand",		// 7
	"jeweled wand",		// 8
	"twisted wand",		// 9
};

static const uint8_t UNIDED_WAND_ATTRS[W_COUNT] = {
	A_BLUE,			// unadorned
	A_CYAN,			// long
	A_CYAN,			// short
	A_INTENSE | A_CYAN,	// crystal
	A_YELLOW,		// wooden
	A_INTENSE | A_YELLOW,	// brass
	A_YELLOW,		// bronze	
	A_MAGENTA,		// jeweled
#ifdef _16COLOR
	A_INTENSE | A_BLACK,	// twisted
#else
	A_BLUE,			// twisted
#endif
};

static const char *UNIDED_WANDS[W_COUNT];

static const char * const UNIDED_POT_SRCS[P_COUNT - 1] = {
	"red potion",		// 1
	"green potion",		// 2
	"translucent potion",	// 3
	"bubbly potion",	// 4
	"fizzy potion",		// 5
	"milky potion",		// 6
	"white potion",		// 7
	"unusual potion",	// 8
	"creamy potion",	// 9
};

static const uint8_t UNIDED_POT_ATTRS[P_COUNT - 1] = {
	A_RED,			// red
	A_GREEN,		// green
	A_CYAN,			// translucent
	A_MAGENTA,		// bubbly
	A_WHITE,		// fizzy
	A_WHITE,		// milky
	A_INTENSE | A_WHITE,	// white
#ifdef _16COLOR
	A_INTENSE | A_BLACK,	// unusual
#else
	A_BLUE,
#endif
	A_BLUE,			// creamy
};

static const char *UNIDED_POTS[P_COUNT];

static uint8_t ITEMATTRS[ID_COUNT];

uint8_t itypeided[ID_COUNT];
char itypedesc[ID_COUNT][64];

item_t *items = NULL;
uint32_t itemcount = 0;
uint32_t itemmax = 0;

void InitItemDescs(void)
{
	uint8_t idx;
	uint8_t roll;
	uint32_t usemask;

	memset(itypeided, 0, ID_COUNT);
	for (idx = 0; idx < ID_COUNT; idx++)
	{
		ITEMATTRS[idx] = ITEMDEFS[idx].attr;
		strcpy(itypedesc[idx], "");
	}

	idx = 0;
	usemask = 0x00000000;
	UNIDED_WANDS[0] = "null wand";
	while (usemask != 0x000001FF)
	{
		roll = rn1(W_COUNT - 1);
		if (usemask & (1 << roll))
		{
			continue;
		}
		usemask |= (1 << roll);
		UNIDED_WANDS[idx + 1] = UNIDED_WAND_SRCS[roll];
		ITEMATTRS[ID_WAND_BASE + idx] = UNIDED_WAND_ATTRS[roll];
		idx++;
	}

	idx = 0;
	usemask = 0x00000000;
	UNIDED_POTS[0] = "clear potion";
	ITEMATTRS[ID_POT_OF_WATER] = A_INTENSE | A_CYAN;
	while (usemask != 0x000001FF)
	{
		roll = rn1(P_COUNT - 1);
		if (usemask & (1 << roll))
		{
			continue;
		}
		usemask |= (1 << roll);
		UNIDED_POTS[idx + 1] = UNIDED_POT_SRCS[roll];
		ITEMATTRS[ID_UNID_POT_BASE + idx] = UNIDED_POT_ATTRS[roll];
		idx++;
	}
}

const char *UnknownItemDesc(uint8_t itype)
{
	if (ITEMDEFS[itype].unidslot != UNID_NONE)
	{
		switch (ITEMDEFS[itype].unidslot)
		{
			case UNID_WAND:
				return UNIDED_WANDS[ITEMDEFS[itype].slot];
			case UNID_POT:
				return UNIDED_POTS[ITEMDEFS[itype].slot];
			default:
				return "thing";
		}
	}
	else
	{
		return ITEMDEFS[itype].name;
	}
}

static uint8_t GenItemOfType(uint8_t cat)
{
	uint16_t roll;
	int8_t enchant;
	uint8_t holiness;
	uint8_t itype;
	uint8_t idx;
	uint16_t total;

	total = 0;
	for (idx = ITEMGENSLOTBASE[cat]; idx < ITEMGENSLOTBASE[cat] + ITEMGENSLOTCOUNT[cat]; idx++)
	{
		total += ITEMDEFS[idx].freq;
	}

	if (!total)
	{
		return 1;
	}

	roll = rn1(total);
	idx = ITEMGENSLOTBASE[cat];
	while (roll > ITEMDEFS[idx].freq)
	{
		roll -= ITEMDEFS[idx].freq;
		idx++;
	}
	itype = idx;

	if (!rn1(8))
	{
		holiness = B_HOLY;
	}
	else if (!rn1(5))
	{
		holiness = B_UNHOLY;
	}
	else if (!rn1(7))
	{
		holiness = B_CURSED;
	}
	else
	{
		holiness = B_NONE;
	}

	enchant = 0;
	switch (holiness)
	{
		case B_NONE:
		case B_UNHOLY:
			roll = rn1(7);
			if (roll == 0)
			{
				enchant = rn3(5);
			}
			else if (roll == 1)
			{
				enchant = -rn3(5);
			}
			break;
		case B_CURSED:
			roll = rn1(3);
			if (roll == 0)
			{
				enchant = -rn3(5);
			}
			break;
		case B_HOLY:
			enchant = 1 + rn2(5);
			break;
	}

	items[itemcount] = BuildItem(itype, enchant, holiness);

	return 0;
}

void GenItemAt(uint8_t x, uint8_t y, uint8_t level, uint8_t branch)
{
	uint16_t roll;
	uint16_t total;
	uint8_t idx;
	uint8_t result;

	if (itemcount >= ITEMMAX)
	{
#ifdef _WIZARD
		AddMsg("You feel you have too many worldly possessions.");
#endif
		return;
	}
	if (itemcount >= itemmax)
	{
		itemmax = itemmax + 20;
		items = (item_t*)realloc(items, sizeof(item_t) * itemmax);
		if (!items)
		{
			AddMsg("The world explodes! You die.");
			GameOver();
			return;
		}
	}

	total = 0;
	for (idx = 0; idx < I_CATCOUNT; idx++)
	{
		total += ITEMGENSLOTS[idx];
	}
	roll = rn1(total);
	idx = 0;
	while (roll > ITEMGENSLOTS[idx])
	{
		roll -= ITEMGENSLOTS[idx];
		idx++;
	}

	if (!ITEMGENSLOTCOUNT[idx])
	{
#ifdef _WIZARD
		AddMsg("You feel as if something is missing from the world.");
#endif
		return;
	}

	result = GenItemOfType(idx);
	if (result)
	{
#ifdef _WIZARD
		AddMsg("You feel the gods are disappointed.");
#endif
		return;
	}
	items[itemcount].x = x;
	items[itemcount].y = y;
	items[itemcount].dlvl = level;
	items[itemcount].branch = branch;
#ifdef _WIZARD
	if (items[itemcount].count == 0)
	{
		AddMsg("You feel that a grevious sin has been committed, type is %i, asked for %i", items[itemcount].type, idx);
	}
#endif
	itemcount++;
}

uint16_t GetItemsAt(uint8_t x, uint8_t y, uint8_t **ids)
{
	uint16_t count;
	uint16_t max;
	uint32_t idx;

	count = 0;
	max = 0;
	*ids = NULL;

	for (idx = 0; idx < itemcount; idx++)
	{
		if (!itemonlvl(idx))
		{
			continue;
		}
		else if (items[idx].x != x || items[idx].y != y)
		{
			continue;
		}
		if (count >= max)
		{
			max = max + 20;
			*ids = (uint8_t*)realloc(*ids, sizeof(uint8_t) * max);
		}
		(*ids)[count] = idx;
		count++;
	}

	return count;
}

void AddItemAt(const item_t *item, uint8_t x, uint8_t y, uint8_t level, uint8_t branch)
{
	if (itemcount >= itemmax)
	{
		itemmax = itemmax + 20;
		items = (item_t*)realloc(items, sizeof(item_t) * itemmax);
		if (!items)
		{
			AddMsg("The world explodes! You die.");
			GameOver();
			return;
		}
	}
#ifdef _WIZARD
	if (item->count == 0)
	{
		AddMsg("You feel empty inside\n");
	}
#endif
	memcpy(&items[itemcount], item, sizeof(item_t));
	items[itemcount].x = x;
	items[itemcount].y = y;
	items[itemcount].dlvl = level;
	items[itemcount].branch = branch;
	itemcount++;
}

void DrawItems(void)
{
	uint32_t idx;
	char ch;

	for (idx = 0; idx < itemcount; idx++)
	{
		if (!itemonlvl(idx))
		{
			continue;
		}
		else if (dexposed(items[idx].x, items[idx].y) < V_WASSEEN)
		{
			continue;
		}
		SetColor(ITEMATTRS[items[idx].type]);
		if (items[idx].type == ID_SILVER_PIECE)
		{
			ch = '$';
		}
		else
		{
			ch = ITEMREPS[ITEMDEFS[items[idx].type].type];
		}
		DrawChar(items[idx].x, DLVL_BASEY + items[idx].y, ch);
	}
}

void DeleteItem(uint32_t itemidx)
{
	memcpy(&items[itemidx], &items[itemcount - 1], sizeof(item_t));
	itemcount--;
}
